package org.budo.redis.jdbc.driver.parser.impl;

import org.budo.jdbc.driver.exception.BudoJdbcDriverNotSupportedException;
import org.budo.jdbc.driver.parser.AbstractSqlStatementParser;
import org.budo.jdbc.driver.statement.AbstractJdbcStatement;
import org.budo.jdbc.driver.statement.JdbcStatement;
import org.budo.redis.jdbc.driver.parser.RedisSqlStatement;
import org.budo.redis.jdbc.driver.statement.key.EXISTS;
import org.budo.redis.jdbc.driver.statement.script.EVAL;
import org.budo.support.lang.util.ReflectUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.slf4j.Slf4j;
import org.slf4j.Logger;

/**
 * @author lmw
 */
public class DefaultRedisStatementParser extends AbstractSqlStatementParser implements ParseConstants {
    private static final Logger log = Slf4j.getLogger();

    @Override
    protected JdbcStatement doParseSql(String sql) throws Throwable {
        if (null == sql || sql.trim().isEmpty()) {
            throw new IllegalStateException("#17 sql is empty, sql=" + sql);
        }

        String functionName = this.parseFunctionName(sql);
        String[] functionParameters = this.parseFunctionParameters(sql);

        if (StringUtil.isEmpty(functionName)) {
            throw new BudoJdbcDriverNotSupportedException("#32 sql=" + sql);
        }

        Class<?> redisFunctionType = this.findRedisFunctionType(functionName); // 效率较低

        if (null == redisFunctionType) {
            throw new BudoJdbcDriverNotSupportedException("#34 unknown functionName=" + functionName + ", sql=" + sql);
        }

        RedisSqlStatement sqlStatement = new RedisSqlStatement(sql, functionName, functionParameters);

        AbstractJdbcStatement redisStatement = (AbstractJdbcStatement) ReflectUtil.newInstance(redisFunctionType);
        redisStatement.setSqlStatement(sqlStatement);

        log.info("#46 parseSelectFunctionStatement, redisStatement=" + redisStatement);
        return redisStatement;
    }

    /**
     * @see #parseFunctionParameters(String)
     */
    private String parseFunctionName(String sql) {
        String functionSql = ParseUtil.functionSql(sql);

        String functionName = ParseUtil.parseFunctionName_2(sql);
        if (null != functionName) {
            return functionName;
        }

        return ParseUtil.parseFunctionName_1(sql, functionSql);
    }

    /**
     * @see #parseFunctionName(String)
     */
    private String[] parseFunctionParameters(String sql) {
        int left = sql.indexOf('(');
        int right = sql.lastIndexOf(')'); // 字符串方式解析不太靠谱

        if (right < 0) { // 未找到函数语法
            return ParseUtil.parseFunctionParameters_2(sql); // 处理特殊语句
        }

        String selectFunction = sql.substring(0, left);
        String functionParameters = sql.substring(left + 1, right); // ('*abc*', 5, 1)

        // 对于EVAL请求,固定只有一个参数,不再去解析里面的逗号等
        if (selectFunction.toUpperCase().trim().endsWith(EVAL.class.getSimpleName())) {
            return new String[] { ParseUtil.parseParameter(functionParameters) };
        }

        String parameterTrim = functionParameters.trim();

        // 特殊语句处理
        // SELECT EXISTS(SELECT key FROM wtf WHERE key=?)
        if (selectFunction.toUpperCase().trim().endsWith(EXISTS.class.getSimpleName())) {
            String parameterUpper = parameterTrim.toUpperCase();
            if (parameterUpper.startsWith("SELECT KEY FROM ")) {
                String WHERE_KEY_EQ = "WHERE KEY=";
                int whereIndex = parameterUpper.indexOf(WHERE_KEY_EQ);
                if (whereIndex > 0) {
                    int len = WHERE_KEY_EQ.length();
                    String parameterValue = parameterTrim.substring(whereIndex + len);
                    return new String[] { ParseUtil.parseParameter(parameterValue) };
                }
            }
        }

        if (parameterTrim.isEmpty()) {
            return new String[0];
        }

        String[] parameterSplit = parameterTrim.split(","); // TODO 如果内容中有逗号, 会造成误判
        String[] parameterArray = new String[parameterSplit.length];

        for (int i = 0; i < parameterSplit.length; i++) {
            parameterArray[i] = ParseUtil.parseParameter(parameterSplit[i]);
        }

        return parameterArray;
    }

    private Class<?> findRedisFunctionType(String functionName) {
        for (String pkg : REDIS_FUNCTION_PACKAGES) {
            String typeName = STATEMENT_PACKAGE + pkg + "." + functionName;
            if (ReflectUtil.hasClass(typeName)) {
                return ReflectUtil.classForName(typeName);
            }
        }

        String typeName = "org.budo.jdbc.driver.statement.impl" + "." + functionName;
        if (ReflectUtil.hasClass(typeName)) {
            return ReflectUtil.classForName(typeName);
        }

        return null;
    }
}